#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <semaphore.h>

template <typename T>
class RingQueue
{
private:
    //--
    void p(sem_t &sem)
    {
        sem_wait(&sem);
    }
    //++
    void v(sem_t &sem)
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void Unlock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int cap)
        : _queue(cap), _cap(cap), _produce_step(0), _consume_step(0)
    {
        sem_init(&_room_sem, 0, _cap);
        sem_init(&_data_sem, 0, 0);

        pthread_mutex_init(&_productor_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);
    }

    ~RingQueue()
    {
        sem_destroy(&_room_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }

    void Enqueue(const T &data)
    {
        // 生产
        p(_room_sem);
        Lock(_productor_mutex);
        // p成功一定有空间
        _queue[_produce_step++] = data;
        _produce_step %= _cap;

        Unlock(_productor_mutex);
        v(_data_sem);
    }

    void Pop(T *data)
    {
        // 消费
        p(_data_sem);
        Lock(_consumer_mutex);
        *data = _queue[_consume_step++];
        _consume_step %= _cap;
        Unlock(_consumer_mutex);
        v(_room_sem);
    }

private:
    // 1 环形队列
    std::vector<T> _queue;
    int _cap;

    // 2 生产和消费下标
    int _produce_step;
    int _consume_step;

    // 3 互斥锁和信号量
    sem_t _room_sem; // 生产者
    sem_t _data_sem; // 消费者
    // 维护多生产和多消费
    pthread_mutex_t _productor_mutex;
    pthread_mutex_t _consumer_mutex;
};